package com.course.complier;

import java.util.Objects;


public class Lexer {
    /**
     * 当前输入已经达到末尾  end of file
     */
    public static final int EOI = 0;
    /**
     * 分号
     */
    public static final int SEMI = 1;
    /**
     * 加号
     */
    public static final int PLUS = 2;
    /**
     * 乘号
     */
    public static final int TIMES = 3;
    /**
     * 左括号
     */
    public static final int LP = 4;
    /**
     * 右括号
     */
    public static final int RP = 5;
    /**
     * 数字或id
     */
    public static final int NUM_OR_ID = 6;
    /**
     * 未知符号
     */
    public static final int UNKNOWN_SYMBOL = 7;


    /**
     * 当前分析到的子字符串指向的是哪个标签token
     */
    private int lookAhead = -1;


    /**
     * 当前分析的子字符串
     */
    public String yytext = "";
    /**
     * 当前分析的子字符串的长度
     */
    public int yyleng = 0;
    /**
     * 当前分析的子字符串的行号
     */
    public int yylineno = 0;



    /**
     * 存储正在分析的语句
     */
    private String current = "";


    public Lexer(String input_buffer) {
        this.current = input_buffer;
    }

    /**
     * 是字符或数字
     *
     * @param c
     * @return
     */
    private boolean isAlnum(char c) {
        if (Character.isAlphabetic(c) == true ||
                Character.isDigit(c) == true) {
            return true;
        }

        return false;
    }


    /**
     * 解析出一个分词，返回分词标签
     *
     * @return
     */
    private int lex() {

        while (true) {

            while (Objects.equals(current, "")) {

                if (current.length() == 0) {
                    current = "";
                    return EOI;
                }

                ++yylineno;
                current.trim();
            }//while (current == "")

            if (current.isEmpty()) {
                return EOI;
            }

            for (int i = 0; i < current.length(); i++) {

                yyleng = 0;
                yytext = current.substring(0, 1);
                switch (current.charAt(i)) {
                    case ';':
                        current = current.substring(1);
                        return SEMI;
                    case '+':
                        current = current.substring(1);
                        return PLUS;
                    case '*':
                        current = current.substring(1);
                        return TIMES;
                    case '(':
                        current = current.substring(1);
                        return LP;
                    case ')':
                        current = current.substring(1);
                        return RP;

                    case '\n':
                    case '\t':
                    case ' ':
                        current = current.substring(1);
                        break;

                    default:
                        if (isAlnum(current.charAt(i)) == false) {
                            return UNKNOWN_SYMBOL;
                        } else {

                            while (i < current.length() && isAlnum(current.charAt(i))) {
                                i++;
                                yyleng++;
                            } // while (isAlnum(current.charAt(i)))

                            yytext = current.substring(0, yyleng);
                            current = current.substring(yyleng);
                            return NUM_OR_ID;
                        }

                } //switch (current.charAt(i))
            }//  for (int i = 0; i < current.length(); i++)

        }//while (true)
    }//lex()


    /**
     * 当前分词是否匹配该标签
     *
     * @param token
     * @return
     */
    public boolean match(int token) {
        if (lookAhead == -1) {
            lookAhead = lex();
        }

        return token == lookAhead;
    }


    /**
     * 向前分词
     */
    public void advance() {
        lookAhead = lex();
    }


    /**
     * 测试分词的功能
     */
    public void runLexer() {
        while (!match(EOI)) {
            System.out.println("Token: " + token() + " ,Symbol: " + yytext);
            advance();
        }
    }

    /**
     * 输出当前标签
     *
     * @return
     */
    private String token() {
        String token = "";
        switch (lookAhead) {
            case EOI:
                token = "EOI";
                break;
            case PLUS:
                token = "PLUS";
                break;
            case TIMES:
                token = "TIMES";
                break;
            case NUM_OR_ID:
                token = "NUM_OR_ID";
                break;
            case SEMI:
                token = "SEMI";
                break;
            case LP:
                token = "LP";
                break;
            case RP:
                token = "RP";
                break;
        }

        return token;
    }
}
